﻿using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using Arch.Client.Services;
using Arch.Common.IoC;
using Microsoft.Practices.Unity;
using Arch.Common.Mapping;
using Arch.Common.Proxy;
using Arch.Client.Proxy;

namespace Arch.Client.IoC
{
    public class ClientDependencyContainer : ArchUnityDependencyContainer
    {
        public const string ServiceToClientCode = "ServiceToClient";
        public const string ClientToServiceCode = "ClientToService";
        public const string ProxyServiceCode = "ProxyServiceCode";


        public override void AutoRegister(IUnityContainer container)
        {

        }

        protected void ConfigureDefaultProxy()
        {
            Container
                .RegisterType<IProxyTypeBuilder, NotifyProxyTypeBuilder>(new ContainerControlledLifetimeManager())
                .RegisterType<IOperationBehavior, NotifyProxyOperationBehavior>(ClientDependencyContainer.ProxyServiceCode)

                .RegisterType<ITypeResolver, ProxyTypeResolver>(ClientDependencyContainer.ServiceToClientCode)
                .RegisterType<ITypeResolver, UnproxyTypeResolver>(ClientDependencyContainer.ClientToServiceCode)

                .RegisterType<IMapper, ReflectionMapper>(ClientDependencyContainer.ServiceToClientCode, 
                    new InjectionConstructor(new ResolvedParameter<ITypeResolver>(ServiceToClientCode)))
                .RegisterType<IMapper, ReflectionMapper>(ClientDependencyContainer.ClientToServiceCode, 
                    new InjectionConstructor(new ResolvedParameter<ITypeResolver>(ClientToServiceCode)))
            ;
        }

        public void RegisterService<TService, TContract>()
            where TService : ClientBase<TContract>, new()
            where TContract : class
        {
            Container.RegisterType<TService>(new InjectionFactory(InstanciateService<TService, TContract>));
        }

        protected TService InstanciateService<TService, TContract>(IUnityContainer container)
            where TService : ClientBase<TContract>, new()
            where TContract : class
        {
            var service = new TService();

            foreach (var op in service.Endpoint.Contract.Operations)
            {
                var proxyOperationBehavior = container.Resolve<IOperationBehavior>(ProxyServiceCode);
                op.Behaviors.Add(proxyOperationBehavior);
            }
            return service;
        }

        public virtual void RegisterModel(IUnityContainer container, Assembly assembly)
        {
            if (assembly != null)
            {
                var proxyCreator = container.Resolve<IProxyTypeBuilder>();

                foreach (var type in assembly.GetTypes())
                {
                    container.RegisterType(type, proxyCreator.GetProxy(type));
                }
            }
        }

    }
}
